
#include "RGame.h"

// RiccssonCoreLib includes.
#include <System/Object.h>
#include <System/String.h>
#include <System/Exception.h>
#include <System/Threading/Thread.h>
#include <System/Text/Encoding.h>
#include <System/Diagnostics/Debug.h>

// Xna includes.
#include "GameTime.h"
#include "Graphics/GraphicsDevice.h"
#include "GraphicsDeviceManager.h"
#include <Riccsson/Xna/Framework/Graphics/_shaders/BuiltinShaders.h>
#include <Riccsson/Xna/Framework/Audio/_SoundEngineWrapper.h>

volatile bool Riccsson::Xna::Framework::Game::initializedComplete = false;

#if Windows
// OpenGL + Windows includes.
#	include <windows.h>		// Header File For Windows
#	include <gl\gl.h>			// Header File For The OpenGL32 Library
#	include <gl\glu.h>			// Header File For The GLu32 Library
#	include <gl\glaux.h>		// Header File For The Glaux Library
#	include <GL\GLee.h>

volatile bool Riccsson::Xna::Framework::Game::renderingEnabled = false;
#else
#	ifdef ref
#	undef ref
#	endif
#	ifdef out
#	undef out
#	endif
#	include <jni.h>
#	include <GLES2/gl2.h>
#	include <GLES2/gl2ext.h>
#	include <pthread.h>
#	include <EGL/egl.h> // requires ndk r5 or newer
#	include <android/native_window.h>
ANativeWindow *_android_window = 0;
bool _android_appRunning = false;
bool _android_appPaused = false;

class EGLClass
{
public:
	enum RenderThreadMessage
	{
		MSG_NONE = 0,
		MSG_WINDOW_SET,
		MSG_RENDER_LOOP_EXIT
	};
 
	pthread_t _threadId;
	pthread_mutex_t _mutex;
	enum RenderThreadMessage _msg;
 
	// android window, supported by NDK r5 and newer
	ANativeWindow* _window;
 
	EGLDisplay _display;
	EGLSurface _surface;
	EGLContext _context;
	int _width;
	int _height;
	GLfloat _angle;
};

#endif

// DEBUG.
#include <Debug.h>

using namespace Riccsson::Xna::Framework;
using namespace Riccsson::Xna::Framework::Graphics;
using namespace Riccsson::System;
using namespace Riccsson::System::Threading;
using namespace Riccsson::System::Text;
using namespace Riccsson::System::Diagnostics;

#pragma region OpenGL Prepearations


static void checkGlError(const char* op)
{
    for (GLint error = glGetError(); error; error = glGetError())
	{
		//LOGI("after %s() glError (0x%x)\n", op, error);
    }
}

bool setupGraphics(int w, int h)
{
	Riccsson::Xna::Framework::Graphics::GraphicsDevice::DeviceScreenWidth = w;
	Riccsson::Xna::Framework::Graphics::GraphicsDevice::DeviceScreenHeight = h;

	if(Riccsson::Xna::Framework::GraphicsDeviceManager::s_singletonInstance != null)
	{
		Riccsson::Xna::Framework::GraphicsDeviceManager::s_singletonInstance->_setupGraphics(w, h);
	}

	glViewport(0, 0, w, h);

	return true;
}

//-----------------------------------------------------------
bool Game::_initialize()
{
	//
	// Load shaders for the sprite batch.
	//
	
	Debug::WriteLine("Game::_initialize() Called.");

#if Windows
	
#elif Android

    const EGLint attribs[] =
	{
        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
		EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, // <--- OpenGL ES 2.0
        EGL_BLUE_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_RED_SIZE, 8,
        EGL_NONE
    };
	EGLint context_attribs[] =
	{
		EGL_CONTEXT_CLIENT_VERSION, 2,
		EGL_NONE
	};

    EGLDisplay display;
    EGLConfig config;
    EGLint numConfigs;
    EGLint format;
    EGLSurface surface;
    EGLContext context;
	EGLint width;
    EGLint height;
    GLfloat ratio;
 
    //LOG_INFO("Initializing context");
 
	Debug::WriteLine("eglGetDisplay() Calling.");
    if ((display = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY)
	{
        //LOG_ERROR("eglGetDisplay() returned error %d", eglGetError());
		Debug::WriteLine("eglGetDisplay() returned error.");
        return false;
    }
 
	Debug::WriteLine("eglInitialize() Calling.");
    if (!eglInitialize(display, 0, 0))
	{
        //LOG_ERROR("eglInitialize() returned error %d", eglGetError());
		Debug::WriteLine("eglInitialize() returned error.");
        return false;
    }

	Debug::WriteLine("eglChooseConfig() Calling.");
    if (!eglChooseConfig(display, attribs, &config, 1, &numConfigs))
	{
        //LOG_ERROR("eglChooseConfig() returned error %d", eglGetError());
		Debug::WriteLine("eglChooseConfig() returned error.");
        //destroy();
        return false;
    }

	Debug::WriteLine("eglGetConfigAttrib() Calling.");
    if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format))
	{
        //LOG_ERROR("eglGetConfigAttrib() returned error %d", eglGetError());
		Debug::WriteLine("eglGetConfigAttrib() returned error.");
        //destroy();
        return false;
    }
 
	Debug::WriteLine("ANativeWindow_setBuffersGeometry() Calling.");
    ANativeWindow_setBuffersGeometry(m_eglClass->_window, 0, 0, format);
 
	Debug::WriteLine("eglCreateWindowSurface() Calling.");
    if (!(surface = eglCreateWindowSurface(display, config, m_eglClass->_window, 0)))
	{
        //LOG_ERROR("eglCreateWindowSurface() returned error %d", eglGetError());
		Debug::WriteLine("eglCreateWindowSurface() returned error");
        //destroy();
        return false;
    }
	
	Debug::WriteLine("eglCreateContext() Calling.");
    if (!(context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attribs)))
	{
		// Error code returned.
		Debug::WriteLine("eglCreateContext() returned error code:");

		// Print error code.
		int errorCode = eglGetError();
		GC_PTR<string> errorCodeStr = Int32((int)errorCode).ToString();
		Debug::WriteLine(errorCodeStr->c_str());

		switch(errorCode)
		{
		case EGL_NOT_INITIALIZED: Debug::WriteLine("EGL_NOT_INITIALIZED"); break;
		case EGL_BAD_ACCESS: Debug::WriteLine("EGL_BAD_ACCESS"); break;
		case EGL_BAD_ALLOC: Debug::WriteLine("EGL_BAD_ALLOC"); break;
		case EGL_BAD_ATTRIBUTE: Debug::WriteLine("EGL_BAD_ATTRIBUTE"); break;
		case EGL_BAD_CONFIG: Debug::WriteLine("EGL_BAD_CONFIG"); break;
		case EGL_BAD_CONTEXT: Debug::WriteLine("EGL_BAD_CONTEXT"); break;
		case EGL_BAD_CURRENT_SURFACE: Debug::WriteLine("EGL_BAD_CURRENT_SURFACE"); break;
		case EGL_BAD_DISPLAY: Debug::WriteLine("EGL_BAD_DISPLAY"); break;
		case EGL_BAD_MATCH: Debug::WriteLine("EGL_BAD_MATCH"); break;
		case EGL_BAD_NATIVE_PIXMAP: Debug::WriteLine("EGL_BAD_NATIVE_PIXMAP"); break;
		case EGL_BAD_NATIVE_WINDOW: Debug::WriteLine("EGL_BAD_NATIVE_WINDOW"); break;
		case EGL_BAD_PARAMETER: Debug::WriteLine("EGL_BAD_PARAMETER"); break;
		case EGL_BAD_SURFACE: Debug::WriteLine("EGL_BAD_SURFACE"); break;
		case EGL_CONTEXT_LOST: Debug::WriteLine("EGL_CONTEXT_LOST"); break;
		default:
			Debug::WriteLine("Unknown error code.");
			break;
		}

        //destroy();
        return false;
    }
 
	Debug::WriteLine("eglMakeCurrent() Calling.");
    if (!eglMakeCurrent(display, surface, surface, context))
	{
        //LOG_ERROR("eglMakeCurrent() returned error %d", eglGetError());
		Debug::WriteLine("eglMakeCurrent() returned error.");
        //destroy();
        return false;
    }
	
	Debug::WriteLine("eglQuerySurface() Calling.");
    if (!eglQuerySurface(display, surface, EGL_WIDTH, &width) || !eglQuerySurface(display, surface, EGL_HEIGHT, &height))
	{
        //LOG_ERROR("eglQuerySurface() returned error %d", eglGetError());
		Debug::WriteLine("eglQuerySurface() returned error.");
        //destroy();
        return false;
    }
 
    m_eglClass->_display = display;
    m_eglClass->_surface = surface;
    m_eglClass->_context = context;
    m_eglClass->_width = width;
    m_eglClass->_height = height;
 
	setupGraphics(width, height);

	Debug::WriteLine("_initialize() Finished.");
#endif
	
	Debug::WriteLine("Game::g_spritebatch_additive_program initialized.");
	g_spritebatch_additive_program = createProgram(gVertexShader, gFragmentShader_additive);
	if (!g_spritebatch_additive_program)
	{
		Debug::WriteLine("OpenGLES: Could not create program.");
	}

	g_spritebatch_additive_gvPositionHandle = glGetAttribLocation(g_spritebatch_additive_program, "a_position");
	g_spritebatch_additive_texCoordSlot = glGetAttribLocation(g_spritebatch_additive_program, "a_texCoord");
	g_spritebatch_additive_gvTexture = glGetUniformLocation(g_spritebatch_additive_program, "s_texture");
	g_spritebatch_additive_iLocFillColor = glGetAttribLocation(g_spritebatch_additive_program, "a_v4FillColor");
	
	Debug::WriteLine("Game::g_spritebatch_opacity_program initialized.");
	g_spritebatch_opacity_program = createProgram(gVertexShader, gFragmentShader_opacity);
	if (!g_spritebatch_opacity_program)
	{
		Debug::WriteLine("OpenGLES: Could not create program.");
	}
	
	g_spritebatch_opacity_gvPositionHandle = glGetAttribLocation(g_spritebatch_opacity_program, "a_position");
	g_spritebatch_opacity_texCoordSlot = glGetAttribLocation(g_spritebatch_opacity_program, "a_texCoord");
	g_spritebatch_opacity_gvTexture = glGetUniformLocation(g_spritebatch_opacity_program, "s_texture");
	g_spritebatch_opacity_iLocFillColor = glGetAttribLocation(g_spritebatch_opacity_program, "a_v4FillColor");
	
	// Use tightly packed data
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

	//Riccsson::Xna::Framework::Audio::_SoundEngineWrapper::getInstance()->play();

    return true;
} 



#if Windows

HDC			hDC=NULL;		// Private GDI Device Context
HGLRC		hRC=NULL;		// Permanent Rendering Context
HWND		hWnd=NULL;		// Holds Our Window Handle
HINSTANCE	hInstance;		// Holds The Instance Of The Application

// Extern variable.
HWND g_hWnd;

bool	keys[256];			// Array Used For The Keyboard Routine
bool	active=TRUE;		// Window Active Flag Set To TRUE By Default
bool	fullscreen=TRUE;	// Fullscreen Flag Set To Fullscreen Mode By Default

#include    <stdio.h>							// Header File For Standard Input/Output ( NEW )
//GLuint      texture[1];                         // Storage For One Texture ( NEW )

int DeviceScreenWidth;
int DeviceScreenHeight;

AUX_RGBImageRec *LoadBMP(const char *Filename)  // Loads A Bitmap Image
{
    FILE *File=NULL;                            // File Handle
	if (!Filename)                              // Make Sure A Filename Was Given
	{
		return NULL;                            // If Not Return NULL
	}
	File=fopen(Filename,"r");                   // Check To See If The File Exists
	if (File)									// Does The File Exist?
	{
		fclose(File);                           // Close The Handle
		return auxDIBImageLoad(Filename);       // Load The Bitmap And Return A Pointer
	}
	return NULL;                                // If Load Failed Return NULL
}

int LoadGLTextures(const char* imageFilename, unsigned int& generatedTexture_out, int& width_out, int& height_out)   // Load Bitmaps And Convert To Textures
{
	int Status=FALSE;                           // Status Indicator
	AUX_RGBImageRec *TextureImage[1];           // Create Storage Space For The Texture
	memset(TextureImage,0,sizeof(void *)*1);    // Set The Pointer To NULL
	
	// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
	if (TextureImage[0]=LoadBMP(imageFilename))
	{
		Status=TRUE;                            // Set The Status To TRUE
		glGenTextures(1, &generatedTexture_out);          // Create The Texture

		// Typical Texture Generation Using Data From The Bitmap
		glBindTexture(GL_TEXTURE_2D, generatedTexture_out);

		// Generate The Texture
		glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

		width_out = TextureImage[0]->sizeX;
		height_out = TextureImage[0]->sizeY;
	}
	
	if (TextureImage[0])                            // If Texture Exists
	{
		if (TextureImage[0]->data)                   // If Texture Image Exists
		{
			free(TextureImage[0]->data);             // Free The Texture Image Memory
		}

		free(TextureImage[0]);                      // Free The Image Structure
	}

	return Status;                              // Return The Status
}

LRESULT	CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)	// Declaration For WndProc
{
	switch(Msg)
    {
    case WM_DESTROY:
		Game::renderingEnabled = false;
        PostQuitMessage(WM_QUIT);
        break;
	case WM_SIZE:
		{
			RECT rect;
			if(GetWindowRect(g_hWnd, &rect))
			{
			  int width = rect.right - rect.left;
			  int height = rect.bottom - rect.top;
			  ReSizeGLScene(width, height);
			}
			break;
		}
    default:
        return DefWindowProc(hWnd, Msg, wParam, lParam);
    }
    return 0;
}

GLvoid KillGLWindow(GLvoid)								// Properly Kill The Window
{
	if (fullscreen)										// Are We In Fullscreen Mode?
	{
		ChangeDisplaySettings(NULL,0);					// If So Switch Back To The Desktop
		ShowCursor(TRUE);								// Show Mouse Pointer
	}

	if (hRC)											// Do We Have A Rendering Context?
	{
		if (!wglMakeCurrent(NULL,NULL))					// Are We Able To Release The DC And RC Contexts?
		{
			MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		}

		if (!wglDeleteContext(hRC))						// Are We Able To Delete The RC?
		{
			MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		}
		hRC=NULL;										// Set RC To NULL
	}

	if (hDC && !ReleaseDC(hWnd,hDC))					// Are We Able To Release The DC
	{
		MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		hDC=NULL;										// Set DC To NULL
	}

	if (hWnd && !DestroyWindow(hWnd))					// Are We Able To Destroy The Window?
	{
		MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		hWnd=NULL;										// Set hWnd To NULL
	}

	if (!UnregisterClass("OpenGL",hInstance))			// Are We Able To Unregister Class
	{
		MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		hInstance=NULL;									// Set hInstance To NULL
	}
}

void ReSizeGLScene(int width, int height);
int InitGL(); // Forward decleration.

/*	This Code Creates Our OpenGL Window.  Parameters Are:					*
 *	title			- Title To Appear At The Top Of The Window				*
 *	width			- Width Of The GL Window Or Fullscreen Mode				*
 *	height			- Height Of The GL Window Or Fullscreen Mode			*
 *	bits			- Number Of Bits To Use For Color (8/16/24/32)			*
 *	fullscreenflag	- Use Fullscreen Mode (TRUE) Or Windowed Mode (FALSE)	*/
 
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{
	GLuint		PixelFormat;			// Holds The Results After Searching For A Match
	WNDCLASS	wc;						// Windows Class Structure
	DWORD		dwExStyle;				// Window Extended Style
	DWORD		dwStyle;				// Window Style
	RECT		WindowRect;				// Grabs Rectangle Upper Left / Lower Right Values
	WindowRect.left=(long)0;			// Set Left Value To 0
	WindowRect.right=(long)width;		// Set Right Value To Requested Width
	WindowRect.top=(long)0;				// Set Top Value To 0
	WindowRect.bottom=(long)height;		// Set Bottom Value To Requested Height

	fullscreen=fullscreenflag;			// Set The Global Fullscreen Flag

	hInstance			= GetModuleHandle(NULL);				// Grab An Instance For Our Window
	wc.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;	// Redraw On Size, And Own DC For Window.
	wc.lpfnWndProc		= (WNDPROC) WndProc;					// WndProc Handles Messages
	wc.cbClsExtra		= 0;									// No Extra Window Data
	wc.cbWndExtra		= 0;									// No Extra Window Data
	wc.hInstance		= hInstance;							// Set The Instance
	wc.hIcon			= LoadIcon(NULL, IDI_WINLOGO);			// Load The Default Icon
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);			// Load The Arrow Pointer
	wc.hbrBackground	= NULL;									// No Background Required For GL
	wc.lpszMenuName		= NULL;									// We Don't Want A Menu
	wc.lpszClassName	= "OpenGL";								// Set The Class Name

	if (!RegisterClass(&wc))									// Attempt To Register The Window Class
	{
		MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;											// Return FALSE
	}
	
	if (fullscreen)												// Attempt Fullscreen Mode?
	{
		DEVMODE dmScreenSettings;								// Device Mode
		memset(&dmScreenSettings,0,sizeof(dmScreenSettings));	// Makes Sure Memory's Cleared
		dmScreenSettings.dmSize=sizeof(dmScreenSettings);		// Size Of The Devmode Structure
		dmScreenSettings.dmPelsWidth	= width;				// Selected Screen Width
		dmScreenSettings.dmPelsHeight	= height;				// Selected Screen Height
		dmScreenSettings.dmBitsPerPel	= bits;					// Selected Bits Per Pixel
		dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

		// Try To Set Selected Mode And Get Results.  NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
		if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
		{
			// If The Mode Fails, Offer Two Options.  Quit Or Use Windowed Mode.
			if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
			{
				fullscreen=FALSE;		// Windowed Mode Selected.  Fullscreen = FALSE
			}
			else
			{
				// Pop Up A Message Box Letting User Know The Program Is Closing.
				MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
				return FALSE;									// Return FALSE
			}
		}
	}

	if (fullscreen)												// Are We Still In Fullscreen Mode?
	{
		dwExStyle=WS_EX_APPWINDOW;								// Window Extended Style
		dwStyle=WS_POPUP;										// Windows Style
		ShowCursor(FALSE);										// Hide Mouse Pointer
	}
	else
	{
		dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;			// Window Extended Style
		dwStyle=WS_OVERLAPPEDWINDOW;							// Windows Style
	}

	AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);		// Adjust Window To True Requested Size

	// Create The Window
	hWnd=CreateWindowEx(	dwExStyle,								// Extended Style For The Window
								"OpenGL",							// Class Name
								title,								// Window Title
								dwStyle |							// Defined Window Style
								WS_CLIPSIBLINGS |					// Required Window Style
								WS_CLIPCHILDREN,					// Required Window Style
								0, 0,								// Window Position
								WindowRect.right-WindowRect.left,	// Calculate Window Width
								WindowRect.bottom-WindowRect.top,	// Calculate Window Height
								NULL,								// No Parent Window
								NULL,								// No Menu
								hInstance,							// Instance
								NULL);								// Dont Pass Anything To WM_CREATE

	if(!hWnd)
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	static	PIXELFORMATDESCRIPTOR pfd=				// pfd Tells Windows How We Want Things To Be
	{
		sizeof(PIXELFORMATDESCRIPTOR),				// Size Of This Pixel Format Descriptor
		1,											// Version Number
		PFD_DRAW_TO_WINDOW |						// Format Must Support Window
		PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
		PFD_DOUBLEBUFFER,							// Must Support Double Buffering
		PFD_TYPE_RGBA,								// Request An RGBA Format
		bits,										// Select Our Color Depth
		0, 0, 0, 0, 0, 0,							// Color Bits Ignored
		0,											// No Alpha Buffer
		0,											// Shift Bit Ignored
		0,											// No Accumulation Buffer
		0, 0, 0, 0,									// Accumulation Bits Ignored
		16,											// 16Bit Z-Buffer (Depth Buffer)  
		0,											// No Stencil Buffer
		0,											// No Auxiliary Buffer
		PFD_MAIN_PLANE,								// Main Drawing Layer
		0,											// Reserved
		0, 0, 0										// Layer Masks Ignored
	};
	
	if (!(hDC=GetDC(hWnd)))							// Did We Get A Device Context?
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))	// Did Windows Find A Matching Pixel Format?
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	if(!SetPixelFormat(hDC,PixelFormat,&pfd))		// Are We Able To Set The Pixel Format?
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	if (!(hRC=wglCreateContext(hDC)))				// Are We Able To Get A Rendering Context?
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	if(!wglMakeCurrent(hDC,hRC))					// Try To Activate The Rendering Context
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	ShowWindow(hWnd,SW_SHOW);						// Show The Window
	SetForegroundWindow(hWnd);						// Slightly Higher Priority
	SetFocus(hWnd);									// Sets Keyboard Focus To The Window
	ReSizeGLScene(width, height);					// Set Up Our Perspective GL Screen

	if (!InitGL())									// Initialize Our Newly Created GL Window
	{
		KillGLWindow();								// Reset The Display
		MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE
	}

	g_hWnd = hWnd;

	return TRUE;									// Success
}

void ReSizeGLScene(int width, int height)		// Resize And Initialize The GL Window
{
	if (height==0)										// Prevent A Divide By Zero By
	{
		height=1;										// Making Height Equal One
	}

	setupGraphics(width, height);

	Riccsson::Xna::Framework::Graphics::GraphicsDevice::DeviceScreenWidth = width;
	Riccsson::Xna::Framework::Graphics::GraphicsDevice::DeviceScreenHeight = height;

	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable( GL_BLEND );

	glViewport(0,0,width,height);						// Reset The Current Viewport

	glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix
	glLoadIdentity();									// Reset The Projection Matrix

	// Calculate The Aspect Ratio Of The Window
	gluPerspective(45.0f,1,0.1f,100.0f);

	glMatrixMode(GL_MODELVIEW);							// Select The Modelview Matrix
	glLoadIdentity();									// Reset The Modelview Matrix

}

int InitGL()										// All Setup For OpenGL Goes Here
{
	glShadeModel(GL_SMOOTH);							// Enable Smooth Shading
	glClearColor(0.0f, 0.0f, 0.0f, 0.5f);				// Black Background
	glClearDepth(1.0f);									// Depth Buffer Setup
	glEnable(GL_DEPTH_TEST);							// Enables Depth Testing
	glDepthFunc(GL_LEQUAL);								// The Type Of Depth Testing To Do
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	// Really Nice Perspective Calculations

	return 1;										// Initialization Went OK
}

#else

//"  gl_FragColor = texture2D( s_texture, v_texCoord );\n"
//"  gl_FragColor = texture2D( s_texture, v_texCoord ).aaaa;\n"
//"  gl_FragColor = vec4( texture2D( s_texture, v_texCoord ).aaa, 1.0 );\n"
//"  gl_FragColor = v_v4FillColor + texture2D( s_texture, v_texCoord );	\n"

#include <jni.h>
#include <android/log.h>

#define  LOG_TAG    "jnitest"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

//-----------------------------------------------------------
void Game::_setWindow(ANativeWindow* window)
{
	Debug::WriteLine("_setWindows() Called.");

	// Notify render thread that window has changed.
    //pthread_mutex_lock(&m_eglClass->_mutex);
    m_eglClass->_msg = EGLClass::MSG_WINDOW_SET;
    m_eglClass->_window = window;
    //pthread_mutex_unlock(&m_eglClass->_mutex); 
}

#endif

#pragma endregion

//---------------------------------------------------------------------------------------
Game::Game()
	: Object()
	, PROP3_INIT(Game, Components)
	, PROP3_INIT(Game, Content)
	, PROP3_INIT(Game, graphicsDevice)
	, PROP3_INIT(Game, InactiveSleepTime)
	, PROP3_INIT(Game, IsActive)
	, PROP3_INIT(Game, IsFixedTimeStep)
	, PROP3_INIT(Game, IsMouseVisible)
	, PROP3_INIT(Game, launchParameters)
	, PROP3_INIT(Game, Services)
	, PROP3_INIT(Game, TargetElapsedTime)
	, PROP3_INIT(Game, Window)
{
	//_oneInstance = this;

	Debug::WriteLine("Game() Begin.");

	Content = new Content::ContentManager(null, STR("raw"));

#if Windows
	// Implement open gl :)
	InitGL();
	ReSizeGLScene(512, 512);
	CreateGLWindow("hej", 512,512,32,false);
	_initialize();
	
#else

	m_eglClass = new EGLClass();
	m_eglClass->_msg = EGLClass::MSG_NONE;
    m_eglClass->_display = 0;
    m_eglClass->_surface = 0;
    m_eglClass->_context = 0;
    m_eglClass->_angle = 0;

	_setWindow(_android_window);

	// Android run the _initialize() on the first draw call.
	//_initialize();
#endif

	Riccsson::System::Diagnostics::Debug::WriteLine("GraphicsDevice::GraphicsDevice() is calling.");
	graphicsDevice = new GraphicsDevice();

	Debug::WriteLine("Game() End.");


}

//---------------------------------------------------------------------------------------
Game::~Game(void)
{
#if Windows
#else
	delete m_eglClass;
	m_eglClass = null;
#endif
}

//---------------------------------------------------------------------------------------
bool Game::BeginDraw()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear Screen And Depth Buffer

#if Windows
	glLoadIdentity();									// Reset The Current Modelview Matrix
	glTranslatef(0.0f,0.0f,-2.0f);						// Move Left 1.5 Units And Into The Screen 6.0
#endif

	return true;
}

//---------------------------------------------------------------------------------------
void Game::BeginRun()
{
	throw;
}

//---------------------------------------------------------------------------------------
void Game::Dispose()
{

}

//---------------------------------------------------------------------------------------
void Game::Dispose(bool disposing)
{

}

//---------------------------------------------------------------------------------------
void Game::Draw(GameTime gameTime)
{
	
}

//---------------------------------------------------------------------------------------
void Game::EndDraw()
{
	
}

//---------------------------------------------------------------------------------------
void Game::EndRun()
{
	throw;
}

//---------------------------------------------------------------------------------------
void Game::Exit()
{
	throw;
}

//---------------------------------------------------------------------------------------
void Game::Initialize()
{
	
}

//---------------------------------------------------------------------------------------
void Game::LoadContent()
{
	
}

//---------------------------------------------------------------------------------------
void Game::OnActivated(object* sender, EventArgs args)
{
	throw;
}

//---------------------------------------------------------------------------------------
void Game::OnDeactivated(object* sender, EventArgs args)
{
	throw;
}

//---------------------------------------------------------------------------------------
void Game::OnExiting(object* sender, EventArgs args)
{
	throw;
}

//---------------------------------------------------------------------------------------
void Game::ResetElapsedTime()
{
	throw;
}

//---------------------------------------------------------------------------------------
void Game::Run()
{
	Debug::WriteLine("Run() Called.");

#if Windows

	// Initialize.
	Initialize();
	Debug::WriteLine("Initialize() Called.");

	// Load contents.
	LoadContent();
	Debug::WriteLine("LoadContent() Called.");

	renderingEnabled = true;
	
	// Windows Message Structure
	MSG	msg;

	initializedComplete = true;

	// Do the simple game loop.
	while(renderingEnabled)
	{
		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))	// Is There A Message Waiting?
		{
			if (msg.message==WM_QUIT)				// Have We Received A Quit Message?
			{
				renderingEnabled = false;
				break;
			}
			else									// If Not, Deal With Window Messages
			{
				TranslateMessage(&msg);				// Translate The Message
				DispatchMessage(&msg);				// Dispatch The Message
			}
		}

		Tick();

		// Swap Buffers (Double Buffering)
		SwapBuffers(hDC);
		
		//Thread::Sleep(10);
	}
#else
	
    while (_android_appRunning)
	{
		if(_android_appPaused)
		{
			Thread::Sleep(100);
		}
		else
		{
			//pthread_mutex_lock(&m_eglClass->_mutex);
 
			// process incoming messages
			switch (m_eglClass->_msg)
			{
				case EGLClass::MSG_WINDOW_SET:
					_initialize();
					
					// Initialize.
					Initialize();
					Debug::WriteLine("Initialize() Called.");

					// Load contents.
					LoadContent();
					Debug::WriteLine("LoadContent() Called.");

					initializedComplete = true;

					break;
				case EGLClass::MSG_RENDER_LOOP_EXIT:
					_android_appRunning = false;
					//destroy();
					break;
				default:
					break;
			}
			m_eglClass->_msg = EGLClass::MSG_NONE;
 
			if (m_eglClass->_display)
			{
				Tick();

				if (!eglSwapBuffers(m_eglClass->_display, m_eglClass->_surface))
				{
					Debug::WriteLine("ERROR eglSwapBuffers.");
					checkGlError("eglSwapBuffers");
					// Error.
				}
			}

			Thread::Sleep(10);
			//pthread_mutex_unlock(&m_eglClass->_mutex);
		}
    } 
	
	Debug::WriteLine("Game loop exit.");

#endif
}

//---------------------------------------------------------------------------------------
void Game::RunOneFrame()
{
	throw;
}

//---------------------------------------------------------------------------------------
bool Game::ShowMissingRequirementMessage(const Exception& exception)
{
	throw;
}

//---------------------------------------------------------------------------------------
void Game::SuppressDraw()
{
	throw;
}

//---------------------------------------------------------------------------------------
void Game::Tick()
{
	// TODO: Both Update() and Draw() must be smarted. If draw is slow, then update bust update more often...
	// Update.
	Update(GameTime());

	// Render.
	if(BeginDraw())
	{
		Draw(GameTime());
		EndDraw();
	}
}

//---------------------------------------------------------------------------------------
void Game::UnloadContent()
{
	throw;
}

//---------------------------------------------------------------------------------------
void Game::Update(GameTime gameTime)
{

}
